/*
 * The MiniQt Library
 *
 * Copyright (C) 1999 Sandro Sigala <ssigala@globalnet.it>
 */

#include <stdio.h>
#include <string.h>
#include <windows.h>

#include "qwidget.h"
#include "qapplication.h"

#define MAX_WINDOW_HANDLES     128

static int wndcounter = 0;
static QWidget *regwnd[MAX_WINDOW_HANDLES];
static int numregwnd = 0;

struct QWidgetPrivate {
	Qt::WFlags flags;
	Qt::WState state;
	QString caption;
	int x, y, width, height;
	char wndName[32];
	WId winid;
};

static LRESULT CALLBACK windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	QWidget *w = QWidget::find(hwnd);
	if (!w)	return DefWindowProc(hwnd, uMsg, wParam, lParam);

	switch (uMsg) {
	case WM_MOVE:
		w->movedTo((int)LOWORD(lParam), (int)HIWORD(lParam));
		break;
	case WM_SIZE:
		w->resizedTo((int)LOWORD(lParam), (int)HIWORD(lParam));
		break;
	case WM_DESTROY:
		if (w == qApp->mainWidget())
			PostQuitMessage(0);
		break;
	case WM_COMMAND:
		if (HIWORD(wParam) == BN_CLICKED) {
			QWidget *btn = QWidget::find((HWND)lParam);
			// Simulate a press and release
			QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress);
			btn->event(e);
			e = new QMouseEvent(QEvent::MouseButtonRelease);
			btn->event(e);
			break;
		}
		break;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

QWidget::QWidget(QWidget *parent, const char *name, WFlags f)
	: QObject(parent, name)
{
#ifdef DEBUG
	qDebug("obj", "QWidget::constructor of \"%s\"", name ? name : "unnamed");
#endif

	d = new QWidgetPrivate;
	d->flags = f;
	d->state = 0;
	d->x = d->y = d->width = d->height = 0;
	d->caption = "nocaption";

	if ((f & WType_Child) == 0) {
		if (parent == 0)
			d->flags |= WType_TopLevel;

		WNDCLASS wc;
		memset(&wc, 0, sizeof(WNDCLASS));
		wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
		wc.lpfnWndProc = windowProc;
		wc.hInstance = hInstance;
		wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
		sprintf(d->wndName, "MainWClass%d", ++wndcounter);
		wc.lpszClassName = d->wndName;
		wc.lpszMenuName = NULL;
		wc.hCursor = LoadCursor(NULL, IDC_ARROW);
		wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
		if (!RegisterClass(&wc))
			qFatal("cannot register window");

		HWND hwnd = CreateWindowEx(
		    0,                      // no extended styles
		    d->wndName,	            // class name
		    d->caption.c_str(),     // window name
		    WS_OVERLAPPEDWINDOW,    // style
	            CW_USEDEFAULT,          // geometry
	            CW_USEDEFAULT,
	            CW_USEDEFAULT,
	            CW_USEDEFAULT,
		    (HWND)NULL,             // no parent or owner window
		    (HMENU)NULL,            // class menu used
		    hInstance,  	    // instance handle
		    NULL);                  // no window creation data

		if (hwnd == (HWND)0)
			qFatal("cannot create window");

		setWinId(hwnd);
		registerWinId(hwnd, this);
	}
	if (parent && parent->isVisible())
		show();
}

QWidget::~QWidget()
{
#ifdef DEBUG
	qDebug("obj", "QWidget::destructor of \"%s\"", name("unnamed"));
#endif
	if (winId() != 0) {
		unregisterWinId(winId());
		DestroyWindow(winId());
	}
	delete d;
}

WId QWidget::winId()
{
	return d->winid;
}

void QWidget::setWinId(WId id)
{
	d->winid = id;
}

QWidget *QWidget::find(WId id)
{
	for (int i = 0; i < numregwnd; ++i)
		if (regwnd[i] && regwnd[i]->winId() == id)
			return regwnd[i];
	return 0;
}

QWidget *QWidget::parentWidget() const
{
	return (QWidget *)parent();
}

bool QWidget::isTopLevel() const
{
	return d->flags & WType_TopLevel;
}

bool QWidget::isWidgetType() const
{
	return TRUE;
}

bool QWidget::isVisible() const
{
	return d->state & WState_Visible;
}

void QWidget::setCaption(const QString& caption)
{
	d->caption = caption;
	SetWindowText(d->winid, caption);
}

const QString& QWidget::caption() const
{
	return d->caption;
}

void QWidget::show()
{
	ShowWindow(d->winid, SW_SHOW);
	d->state |= WState_Visible;
	QObjectList olist = *children();
	for (QObject *o = olist.first(); o != 0; o = olist.next()) {
		if (o->isWidgetType())
			((QWidget *)o)->show();
	}
}

void QWidget::hide()
{
	ShowWindow(d->winid, SW_HIDE);
	d->state &= ~WState_Visible;
	QObjectList olist = *children();
	for (QObject *o = olist.first(); o != 0; o = olist.next()) {
		if (o->isWidgetType())
			((QWidget *)o)->hide();
	}
}

bool QWidget::close()
{
	return FALSE;
}

void QWidget::event(QEvent *e)
{
	switch (e->type()) {
	case QEvent::None:
		delete e;
		break;
	case QEvent::MouseButtonPress: {
		QMouseEvent *me = (QMouseEvent *)e;
		mousePressEvent(me);
		delete me;
		break;
	}
	case QEvent::MouseButtonRelease: {
		QMouseEvent *me = (QMouseEvent *)e;
		mouseReleaseEvent(me);
		delete me;
		break;
	}
	}
}

void QWidget::mousePressEvent(QMouseEvent * /*e*/)
{
}

void QWidget::mouseReleaseEvent(QMouseEvent * /*e*/)
{
}

void QWidget::movedTo(int x, int y)
{
	d->x = x;
	d->y = y;
}

void QWidget::resizedTo(int width, int height)
{
	d->width = width;
	d->height = height;
}

void QWidget::move(int x, int y)
{
	d->x = x;
	d->y = y;
	MoveWindow(d->winid, d->x, d->y, d->width, d->height, TRUE);
}

void QWidget::resize(int width, int height)
{
	d->width = width;
	d->height = height;
	MoveWindow(d->winid, d->x, d->y, d->width, d->height, TRUE);
}

void QWidget::setGeometry(int x, int y, int width, int height)
{
	d->x = x;
	d->y = y;
	d->width = width;
	d->height = height;
	MoveWindow(d->winid, d->x, d->y, d->width, d->height, TRUE);
}

void QWidget::registerWinId(WId id, QWidget *w)
{
#ifdef DEBUG
	qDebug("wid", "registering window ID %p \"%s\"", id, w->name());
#endif
	for (int i = 0; i < numregwnd; ++i)
		if (!regwnd[i]) {
			regwnd[i] = w;
			return;
		}
	if (numregwnd >= MAX_WINDOW_HANDLES)
		qFatal("maximum number of window handles exceed");
	else
		regwnd[numregwnd++] = w;
}

void QWidget::unregisterWinId(WId id)
{
#ifdef DEBUG
	qDebug("wid", "unregistering window ID %p", id);
#endif
	for (int i = 0; i < numregwnd; ++i)
		if (regwnd[i] && regwnd[i]->winId() == id) {
			regwnd[i] = 0;
			break;
		}
}
